const Acan = require('../lib/Acan')
const { fork } = require('child_process')
const os = require('os')
const cpuNum = os.cpus().length
const pool = []
const pcount = { inc: 0 }
const pinit = []
global.qpsfork = {}
const worketCall = {
  0(rs) { // 进程启动完成通知
    pinit.push(1)
    if (pinit.length === conf.fork) worketCall.init() // 进程启动完毕
  },
  1(...args) {},
  2(pid, rs) { // 同步子进程统计
    qpsfork[pid] = rs
  },
  3(pid, rs) { // cpu 回调
    Adebug.log(pid, rs)
  }
}

const actCount = { create: { inc: 0 } }
global.actRate = {}
let last
let lastCpu = process.cpuUsage()
const cpuRate = {}
setInterval(() => {
  // 计算每秒CPU使用率
  const nowCpu = process.cpuUsage()
  cpuRate.user = nowCpu.user - lastCpu.user
  cpuRate.system = nowCpu.system - lastCpu.system
  lastCpu = nowCpu
  // 计算每秒请求量
  const now = {}
  Acan.each(actCount, (fn, k) => { now[k] = fn.inc })
  if (last) {
    Acan.each(now, (v, k) => {
      if (!v || !last[k]) return
      actRate[k] = v - last[k]
    })
  }
  last = now
}, 1000)

const mod = {
  async cpu() {
    const data = await this.proxyAll('cpu')
    data.unshift(Object.assign({ pid: process.pid, isMaster: true }, cpuRate))
    const rs = { user: 0, system: 0, cpu: 0, data }
    data.map(cpu => {
      rs.user += cpu.user
      rs.system += cpu.system
      rs.cpu += cpu.user + cpu.system
    })
    rs.user = (rs.user / cpuNum / 10000).toFixed(2)
    rs.system = (rs.system / cpuNum / 10000).toFixed(2)
    rs.cpu = (rs.cpu / cpuNum / 10000).toFixed(2)
    return rs
  },
  start() {
    const worker = fork(__dirname + '/thc.js')
    worker.calls = {}
    worker.inc = 11
    worker.on('message', (arr) => {
      const id = arr.shift()
      const act = arr.shift()
      if (id > 10) {
        if (!actCount[act]) actCount[act] = { inc: 0 }
        if (act === 'creates') actCount.create.inc += (arr[0] || {}).count
        actCount[act].inc++
      }
      if (worker.calls[id]) worker.calls[id].apply(worker.calls[id], arr)
      else if (worketCall[id]) worketCall[id].apply(worker.calls[id], arr)
      else Adebug.log(id, `${id} not found`, arr)
      if (id > 10) delete worker.calls[id]
    })
    worker.send([0, 'conf', conf])
    // for (const ns in tables) {
    //   if (ns !== 'tt.test') continue
    //   const o = {}
    //   const arr = [0, 'initTable']
    //   for (const key of Object.keys(tables[ns])) {
    //     if (['_sab', '_buf'].includes(key)) continue
    //     if (Acan.isFun(tables[ns][key])) continue
    //     o[key] = tables[ns][key]
    //   }
    //   arr.push(o)
    //   arr.push(Object.keys(tables[ns]._sab))
    //   for (const k of arr[3]) {
    //     arr.push(tables[ns]._sab[k])
    //   }
    //   worker.send(arr)
    // }
    pool.push(worker)
  },
  init(cb) {
    conf.fork = conf.fork || 1
    for (let i = 0; i < conf.fork; i++) {
      mod.start()
    }
    worketCall.init = cb
  },
  proxyAll(...args) {
    const prr = []
    args.unshift(0)
    pool.map(worker => {
      prr.push(new Promise(res => {
        const id = worker.inc
        args[0] = id
        worker.calls[id] = res
        worker.send(args)
        worker.inc++
      }))
    })
    return Promise.all(prr)
  },
  proxy(...args) {
    const worker = pool[pcount.inc]
    if (!worker.connected) return
    const id = worker.inc
    args.unshift(id)
    worker.inc++
    pcount.inc++
    if (pcount.inc >= pool.length) pcount.inc = 0
    worker.calls[id] = args.pop()
    worker.send(args)
  },
  proxyTable(...args) {
    args.unshift('table')
    return mod.proxy.apply(mod, args)
  }
}
module.exports = mod
